package br.com.mundodaprata.store.data.jpa;

import java.util.Collections;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.NoResultException;
import javax.persistence.TypedQuery;

import br.com.mundodaprata.store.data.Repository;

public class RepositoryJPA<T> 
					implements Repository<T> {
	
	private EntityManager em;
	private Class<T> type;
	
	public RepositoryJPA(Class<T> type) {
		super();
		this.type = type;
	}
	
	protected Class<T> getType() {
		return type;
	}

	public void setEntityManager(EntityManager em) {
		this.em = em;
	}
	
	protected EntityManager getEntityManager() {
		return em;
	}

	@Override
	public void insert(final T... elements) throws Exception {
		Runnable insert = new Runnable() {
			@Override
			public void run() {
				for (T element : elements) {
					em.persist(element);
				}
			}
		};
		
		runInTransaction(insert);
	}

	@Override
	public void update(final T... elements) throws Exception {
		Runnable update = new Runnable() {
			@Override
			public void run() {
				for (T element : elements) {
					em.merge(element);
				}
			}
		};
		
		runInTransaction(update);
	}

	@Override
	public void remove(final T... elements) throws Exception {
		Runnable remove = new Runnable() {
			@Override
			public void run() {
				for (T element : elements) {
					em.remove(element);
				}
			}
		};
		
		runInTransaction(remove);
	}

	@Override
	public void closeConnection() {
		
	}

	@Override
	public T select(Long key) {
		return em.find(type, key);
	}

	@Override
	public List<T> all() {
		String jpql = "select e from " + 
							type.getSimpleName() +
							" e";
		
		TypedQuery<T> query = 
						em.createQuery(jpql, type);
		
		try {
			return query.getResultList();
		} catch (NoResultException e) {
			return Collections.emptyList();
		}
	}
	
	private void runInTransaction(Runnable runnable){
		EntityTransaction transaction = 
				em.getTransaction();

		if(!transaction.isActive()){
			transaction.begin();
		}

		try {
			runnable.run();
			transaction.commit();
		} catch (Exception e) {
			if(transaction.isActive()){
				transaction.rollback();
			}
			
			throw new RuntimeException(e);
		}
	}

}